package com.ceair.flight.refund.service.appmobile.impl;

import com.ceair.flight.refund.dto.appmoblie.AddAttachmentRes;
import com.ceair.flight.refund.dto.appmoblie.CalculateFeeReq;
import com.ceair.flight.refund.dto.appmoblie.CalculateFeeRes;
import com.ceair.flight.refund.dto.appmoblie.ChangePersonPhoneReq;
import com.ceair.flight.refund.dto.appmoblie.ChangePersonPhoneRes;
import com.ceair.flight.refund.dto.external.PriceSolutionRequest;
import com.ceair.flight.refund.dto.external.RefundablePrice;
import com.ceair.flight.refund.dto.ota.RefundAttachmentReq;
import com.ceair.flight.refund.location.dao.IPaxDao;
import com.ceair.flight.refund.location.dao.IRefundApplyDao;
import com.ceair.flight.refund.location.dao.IRefundSegDao;
import com.ceair.flight.refund.location.dao.IRefundTktDao;
import com.ceair.flight.refund.location.dt.enums.CardTypeEnum;
import com.ceair.flight.refund.location.dt.enums.MethodEnum;
import com.ceair.flight.refund.location.dt.enums.RefundStatus;
import com.ceair.flight.refund.location.model.FlightOrderDO;
import com.ceair.flight.refund.location.model.OrderDO;
import com.ceair.flight.refund.location.model.PaxDO;
import com.ceair.flight.refund.location.model.RefundApplyDO;
import com.ceair.flight.refund.location.model.RefundSegDO;
import com.ceair.flight.refund.location.model.RefundTktDO;
import com.ceair.flight.refund.location.service.IRefundLocationService;
import com.ceair.flight.refund.service.IOrderService;
import com.ceair.flight.refund.service.IRefundTicketService;
import com.ceair.flight.refund.service.appmobile.IAppRefundService;
import com.ceair.flight.refund.service.external.calculator.IRefundFeeSolution;
import com.ceair.flight.refund.service.notification.IRefundFailNotification;
import com.ceair.flight.refund.util.Constants;
import com.ceair.flight.refund.util.CurrencyUtil;
import com.ceair.flight.refund.util.DBUtil;
import com.ceair.flight.refund.util.GsonUtil;
import com.ceair.muservice.filemanager.feign.IAppRefundFileManager;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @Description app退单服务
 */
@Service("appRefundService")
@Path("/")
public class AppRefundServiceImpl implements IAppRefundService {
    private static final Logger LOG = LoggerFactory.getLogger(AppRefundServiceImpl.class);

    @Autowired
    private IRefundApplyDao refundApplyDao;

    @Autowired
    private IRefundLocationService refundLocationService;

    @Autowired
    private IRefundTktDao refundTktDao;

    @Autowired
    private IPaxDao paxDao;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IRefundTicketService refundTicketService;

    @Autowired
    private IRefundFeeSolution eCFareRefundFeeSolution;

    @Autowired
    private IRefundSegDao refundSegDao;

    @Autowired
    @Qualifier("dbUtil")
    private DBUtil dbUtil;

    @Autowired
    private IAppRefundFileManager appRefundFileManager;

    @Autowired
    private IRefundFailNotification refundFailNotification;

    /**
     * 修改联系人手机号
     */
    @Override
    @POST
    @Path("/changePersonPhone")
    @Consumes({"application/json"})
    @Produces(MediaType.APPLICATION_JSON)
    public ChangePersonPhoneRes changePersonPhone(ChangePersonPhoneReq req) {
        LOG.info("修改联系人手机号,入参为：{}", GsonUtil.toJson(req));
        ChangePersonPhoneRes res = new ChangePersonPhoneRes();
        if (!checkChangePersonPhoneParam(req)) {
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.PARAMS_ERROR_MSG);
            return res;
        }
        RefundApplyDO refundApplyDO = refundApplyDao.getRefundApplyById(req.getApplyId());
        if (refundApplyDO == null) {
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.EMPTY_MSG);
            return res;
        }
        // todo 校验手机号码
        RefundApplyDO refundApplyNew = new RefundApplyDO();
        refundApplyNew.setClaimerPhone(req.getPersonPhone());
        refundApplyNew.setId(req.getApplyId());
        try {
            refundApplyDao.changePhone(refundApplyNew);
            res.setResultCode(Constants.SUCCESS_CODE);
            res.setResultMsg(Constants.SUCCESS_MSG);
            LOG.info("修改联系人手机号成功！applyId:{},phone:{}", req.getApplyId(), req.getPersonPhone());
            return res;
        } catch (Exception e) {
            LOG.error("系统异常:{}", e.getMessage());
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.SERVER_ERROR_MSG);
            return res;
        } catch (Error ex) {
            LOG.error("修改联系人手机号失败" + ex.getMessage());
            res.setResultCode("1");
            res.setResultMsg("修改联系人手机号失败处理失败");
            return res;
        }
    }

    /**
     * 重新提交申请:在退票审核被拒绝之后，重新发起退票申请
     */
    @Override
    @POST
    @Path("/reapply")
    @Consumes({"application/json"})
    @Produces(MediaType.APPLICATION_JSON)
    public CalculateFeeRes reapply(CalculateFeeReq req) {
        LOG.info("开始重新提交申请，入参：{}", GsonUtil.toJson(req));
        CalculateFeeRes res = new CalculateFeeRes();
        if (!checkReApplyParam(req)) {
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.PARAMS_ERROR_MSG);
            return res;
        }
        try {
            RefundApplyDO refundApplyDO = refundLocationService.getRefundApply(req.getApplyInfo().getApplyId());
            if (refundApplyDO == null) {
                res.setResultCode(Constants.ERROR_CODE);
                res.setResultMsg(Constants.EMPTY_MSG);
                return res;
            }
            //TODO
            String applyStatus = refundApplyDO.getStatus();
            if (!RefundStatus.WAIT_USER_UPDATE.getCode().equals(applyStatus)) {
                res.setResultCode("1");
                res.setResultMsg("当前退票状态不允许重新提交申请");
                return res;
            }

            refundApplyDO.setStatus(RefundStatus.WAIT_FIRST_AUDIT.getCode());
            boolean isSuccess = refundLocationService.reApply(refundApplyDO);
            if (isSuccess) {
                res.setResultCode(Constants.SUCCESS_CODE);
                res.setResultMsg(Constants.SUCCESS_MSG);
            } else {
                res.setResultCode(Constants.ERROR_CODE);
                res.setResultMsg(Constants.SERVER_ERROR_MSG);
            }
            return res;
        } catch (Exception e) {
            refundFailNotification.sendRefundFailMail(req.getApplyInfo().getOrderNo());
            LOG.error("ReApply error:", e);
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.SERVER_ERROR_MSG);
            return res;
        } catch (Error ex) {
            refundFailNotification.sendRefundFailMail(req.getApplyInfo().getOrderNo());
            LOG.error("ReApply error:", ex);
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.SERVER_ERROR_MSG);
            return res;
        }
    }

    /**
     * 非自愿退货被拒绝后转自愿退票
     */
    @Override
    @POST
    @Path("/recalcfee")
    @Consumes({"application/json"})
    @Produces(MediaType.APPLICATION_JSON)
    public CalculateFeeRes recalcfee(CalculateFeeReq request) {
        LOG.info("非自愿转自愿退票,入参:{}", GsonUtil.toJson(request));
        CalculateFeeRes res = new CalculateFeeRes();
        if (!checkrecalcfeeParam(request)) {
            res.setResultCode(Constants.ERROR_CODE);
            res.setResultMsg(Constants.PARAMS_ERROR_MSG);
            return res;
        }
        try {
            // 查询乘客退票申请信息
            long applyId = request.getApplyInfo().getApplyId();
            RefundApplyDO refundApplyDO = refundApplyDao.getRefundApplyById(applyId);
            // 状态必须为非自愿且一审拒绝才能做后续处理
            if (RefundStatus.WAIT_USER_UPDATE.getCode().equals(refundApplyDO.getStatus()) && refundApplyDO.getIsVoluntary() == 0) {
                // 查询退票乘客及票信息
                RefundTktDO refundTkt = refundTktDao.selectByApplyId(applyId);
                Long paxId = refundTkt.getPaxId();
                //状态 1待开票、2已开票、3已退票、4已改期、5已升舱、6已挂起
                PaxDO paxDO = paxDao.queryPaxById(paxId);
                if (3 != paxDO.getModifySt()){
                    res.setResultCode("1");
                    res.setResultMsg("抱歉，不允许非自愿转自愿退票");
                    return res;
                }

                OrderDO orderDO = orderService.queryFlightOrderDetail(request.getApplyInfo().getOrderNo());
                Set<FlightOrderDO> flightOrderDOS = orderDO.getFlightOrders();
                FlightOrderDO flightOrderDO = null;
                for (FlightOrderDO flightOrder:flightOrderDOS){
                    if (flightOrder.getFlightOrderNo().equals(refundTkt.getFlightOrderNo())){
                        flightOrderDO = flightOrder;
                        break;
                    }
                }

                BigDecimal ecRefundFee = getECRefundFee(refundTkt,orderDO,refundApplyDO, MethodEnum.REFUND_APPLY);
                BigDecimal oldRefundAmount = refundApplyDO.getRefundAmount();
                Long newRefundPoints = getRefundPoints(flightOrderDO,refundTkt);

                //更改退票单
                RefundTktDO refundTktNew = new RefundTktDO();
                refundTktNew.setId(refundTkt.getId());
                refundTktNew.setRefundFee(ecRefundFee);
                BigDecimal refundAmt = refundTkt.getRefundAmt().subtract(ecRefundFee);
                refundTktNew.setRefundAmt(refundAmt.compareTo(BigDecimal.ZERO)<0?BigDecimal.ZERO:refundAmt);
                refundTktNew.setRefundPoints(newRefundPoints);
//                refundTktNew.setApplyId(refundTkt.getApplyId());
                refundTktNew.setId(refundTkt.getId());

                //更改退票申请
                RefundApplyDO refundApplyNew = new RefundApplyDO();
                refundApplyNew.setId(refundApplyDO.getId());
                refundApplyNew.setRefundFee(ecRefundFee);
                BigDecimal refundAmount = oldRefundAmount.subtract(ecRefundFee);
                refundApplyNew.setRefundAmount(refundAmount.compareTo(BigDecimal.ZERO)<0?BigDecimal.ZERO:refundAmount);
                refundApplyNew.setRefundPoints(newRefundPoints);
                refundApplyNew.setIsVoluntary(1);
                refundApplyNew.setStatus("209");
                //TODO 待确认是否需要变更退票原因
                refundApplyNew.setClaimReason("10");

                boolean isSuccess = refundTicketService.recalFeeService(refundApplyNew,refundTktNew);
                if (isSuccess){
                    res.setResultCode("0");
                    res.setResultMsg("非自愿转自愿退票处理成功");
                }else {
                    res.setResultCode("1");
                    res.setResultMsg("非自愿转自愿退票处理失败");
                }
            } else {
                res.setResultCode("2");
                res.setResultMsg("当前状态不是非自愿一审异常，退票处理失败");
                return res;
            }

            LOG.info("非自愿转自愿处理结束，出参：" + new Gson().toJson(res));
        } catch (Exception e) {
            refundFailNotification.sendRefundFailMail(request.getApplyInfo().getOrderNo());
            LOG.error("非自愿转自愿退票处理失败" + e.getMessage());
            res.setResultCode("1");
            res.setResultMsg("非自愿转自愿退票处理失败");
            return res;
        } catch (Error ex){
            refundFailNotification.sendRefundFailMail(request.getApplyInfo().getOrderNo());
            LOG.error("非自愿转自愿退票处理失败" + ex.getMessage());
            res.setResultCode("1");
            res.setResultMsg("非自愿转自愿退票处理失败");
            return res;
        }
        return res;
    }

    @Override
    @POST
    @Path("/addAttachment")
    @Consumes({"application/json"})
    @Produces(MediaType.APPLICATION_JSON)
    public AddAttachmentRes addAttachment(RefundAttachmentReq req) {
        boolean isPass = checkAddAttachmentParam(req);
        com.ceair.muservice.filemanager.dto.refund.RefundAttachmentReq refundAttachmentReq =
                new com.ceair.muservice.filemanager.dto.refund.RefundAttachmentReq();
        refundAttachmentReq.setApplyId(req.getApplyId());
        refundAttachmentReq.setContent(req.getContent());
        refundAttachmentReq.setName(req.getName());
        refundAttachmentReq.setSalesChannel(req.getSalesChannel());
        com.ceair.muservice.filemanager.dto.BaseRes baseRes = appRefundFileManager.addAttachment(refundAttachmentReq);
        AddAttachmentRes res = new AddAttachmentRes();
        res.setResultCode(baseRes.getResultCode());
        res.setResultMsg(baseRes.getResultMsg());
        return res;
    }

    private boolean checkAddAttachmentParam(RefundAttachmentReq req) {
        boolean result = true;
        if (StringUtils.isEmpty(req.getApplyId()) || StringUtils.isEmpty(req.getName())||
            StringUtils.isEmpty(req.getContent()) || StringUtils.isEmpty(req.getSalesChannel())){
            result = false;
        }
        return result;
    }

    @POST
    @Path("/test")
    @Consumes({"application/json"})
    @Produces(MediaType.APPLICATION_JSON)
    @Override
    public void test(String string) {

        try {
            List<Long> subList = new ArrayList<>();
//            (109513,109534,109601,109602,109462);
            subList.add(752l);
            subList.add(772l);
            subList.add(773l);
            subList.add(812l);
            subList.add(832l);
            List<Object[]> objects = new ArrayList<>();
            for (Long appId:subList){
                Object[] arr = new Object[3];
                arr[0] = "401";
                arr[1] = new Date();
                arr[2] = appId;
                objects.add(arr);
            }
//            String sql = "update  T_REFUND_APPLY set STATUS=?,UPDAT_DATE=? where ID = ? ";
            String sql = "update  T_REFUND_APPLY_DEPUTY set STATUS=?,UPDATE_DATE=? where ID = ? ";
            dbUtil.batchUpdate(sql,objects);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 校验修改联系人手机号码入参
     *
     * @param req
     * @return
     */
    private boolean checkChangePersonPhoneParam(ChangePersonPhoneReq req) {
        boolean result = true;
        if (StringUtils.isEmpty(req.getSalesChannel()) || req.getApplyId() == null || req.getPassportId() == null || StringUtils.isEmpty(req.getPersonPhone())) {
            result = false;
        }
        return result;
    }

    /**
     * 校验重新申请入参
     *
     * @param req
     * @return
     */
    private boolean checkReApplyParam(CalculateFeeReq req) {
        boolean result = true;
        if (StringUtils.isEmpty(req.getSalesChannel()) || !("refund".equals(req.getDruidStageCode())) || req.getApplyInfo() == null || req.getApplyInfo().getApplyId() == null) {
            result = false;
        }
        return result;
    }

    /**
     * 校验非自愿转自愿退票入参
     *
     * @param req
     * @return
     */
    private boolean checkrecalcfeeParam(CalculateFeeReq req) {
        boolean result = true;
        if (StringUtils.isEmpty(req.getSalesChannel()) || !("refund".equals(req.getDruidStageCode())) || req.getApplyInfo() == null || req.getApplyInfo().getApplyId() == null) {
            result = false;
        }
        return result;
    }

    private Long getRefundPoints(FlightOrderDO flightOrderDO, RefundTktDO refundTkt) {
        long pointsRefund = 0L;
        //判断是否是白金白金购买者
        String buyerTypeCode = flightOrderDO.getCardType();
        CardTypeEnum buyerType = null;
        if (buyerTypeCode != null && !buyerTypeCode.isEmpty()) {
            buyerType = CardTypeEnum.getByCode(buyerTypeCode);
        }
        if (buyerType == CardTypeEnum.PLT) {
            pointsRefund = getTotalPoints(flightOrderDO,refundTkt.getTicketNo());
            LOG.info("PLT buyer refund all points: {}", pointsRefund);
        }
        return pointsRefund;
    }

    private Long getTotalPoints(FlightOrderDO flightOrder,String ticketNo) {
        Set<PaxDO> paxes = flightOrder.getPaxs();
        for (PaxDO pax : paxes) {
            if (pax.getTktNo().equals(ticketNo)) {
                return pax.getPointAmount().longValue();
            }
        }
        return 0L;
    }

    private BigDecimal getECRefundFee(RefundTktDO refundTkt, OrderDO orderDO, RefundApplyDO refundApplyDO, MethodEnum methodEnum) {
        BigDecimal refundFee = BigDecimal.ZERO;
        Set<FlightOrderDO> flightOrderDOS = orderDO.getFlightOrders();
        FlightOrderDO flightOrderDO = null;
        for (FlightOrderDO flightOrder:flightOrderDOS){
            if (flightOrder.getFlightOrderNo().equals(refundTkt.getFlightOrderNo())){
                flightOrderDO = flightOrder;
                break;
            }
        }

        if(flightOrderDO.getCardType() != null && !"".equals(flightOrderDO.getCardType()) && CardTypeEnum.PLT.getCode().equals(flightOrderDO.getCardType())){
            String pointTp = flightOrderDO.getPointTp();//pointTP有值，不为空说明是积分票
            if ("SJF".equals(pointTp)){
                return BigDecimal.ZERO;
            }
        }

        PriceSolutionRequest priceSolutionRequest = buildPriceSolutionRequest(refundTkt,orderDO,refundApplyDO,flightOrderDO);
        RefundablePrice refundablePrice = eCFareRefundFeeSolution.getRefundFee(priceSolutionRequest,methodEnum);
        refundFee = refundablePrice.getFeeAmount();
        String currency = priceSolutionRequest.getCurrency();
        return CurrencyUtil.getProfitableValue(currency, refundFee);
    }

    private PriceSolutionRequest buildPriceSolutionRequest(RefundTktDO refundTkt, OrderDO orderDO, RefundApplyDO refundApplyDO, FlightOrderDO flightOrderDO) {
        PriceSolutionRequest priceSolutionRequest = new PriceSolutionRequest(refundTkt.getTicketNo());
        priceSolutionRequest.setBigOrder(orderDO);
        priceSolutionRequest.setPnrCancelDate(refundApplyDO.getPnrCancelDate());
        List<RefundSegDO> refundSegDOS = refundSegDao.queryByRfdTktId(refundTkt.getId());
        priceSolutionRequest.setFlightOrder(flightOrderDO);
        priceSolutionRequest.setRefundSegIndex(refundSegDOS.get(0).getIndexNo());
        return priceSolutionRequest;
    }
}
